package org.dromara.gateway.route;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.gateway.config.properties.DynamicRouteProperties;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * 获取动态路由配置
 *
 * @author shuai.zhou
 */
@Slf4j
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private final NacosConfigManager nacosConfigManager;

    private final DynamicRouteProperties dynamicRouteProperties;

    public NacosRouteDefinitionRepository(NacosConfigManager nacosConfigManager, DynamicRouteProperties dynamicRouteProperties) {
        this.nacosConfigManager = nacosConfigManager;
        this.dynamicRouteProperties = dynamicRouteProperties;
        addListener();
    }

    /**
     * NacosRouteDefinitionRepository会从Nacos读取【portal_dynamic_routes.json】的路由配置并加载到内存
     *
     * @author shuai.zhou
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            String content = nacosConfigManager.getConfigService().getConfig(dynamicRouteProperties.getDataId(), dynamicRouteProperties.getDataGroup(), 5000);
            if (StringUtils.isBlank(content)) {
                return Flux.fromIterable(CollUtil.newArrayList());
            }
            List<RouteDefinition> routeDefinitionList = JSONUtil.toList(content, RouteDefinition.class);
            return Flux.fromIterable(routeDefinitionList);
        } catch (NacosException e) {
            log.error("getRouteDefinitions by nacos error:", e);
        }
        return Flux.fromIterable(CollUtil.newArrayList());
    }

    /**
     * 注册Nacos配置变更监听器,当检测到路由配置变化时,发布【RefreshRoutesEvent】事件
     *
     * @author shuai.zhou
     */
    private void addListener() {
        try {
            nacosConfigManager.getConfigService().addListener(dynamicRouteProperties.getDataId(), dynamicRouteProperties.getDataGroup(), new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("Naocs动态路由配置更新.");
                    // Gateway监听到【RefreshRoutesEvent】后,会调用【RouteDefinitionLocator】重新加载路由配置,实现动态更新
                    SpringUtils.context().publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            log.error("nacos addListener error:", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return Mono.empty();
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return Mono.empty();
    }

}
